home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Celestin Apprentice 5
/
Apprentice-Release5.iso
/
Source Code
/
Libraries
/
DCLAP 6d
/
dclap6d
/
network
/
nsclilib
/
ni_encr.c
< prev
next >
Wrap
Text File
|
1996-07-05
|
30KB
|
998 lines
/*
* ===========================================================================
*
* PUBLIC DOMAIN NOTICE
* National Center for Biotechnology Information
*
* This software/database is a "United States Government Work" under the
* terms of the United States Copyright Act. It was written as part of
* the author's official duties as a United States Government employee and
* thus cannot be copyrighted. This software/database is freely available
* to the public for use. The National Library of Medicine and the U.S.
* Government have not placed any restriction on its use or reproduction.
*
* Although all reasonable efforts have been taken to ensure the accuracy
* and reliability of the software and data, the NLM and the U.S.
* Government do not and cannot warrant the performance or results that
* may be obtained by using this software or data. The NLM and the U.S.
* Government disclaim all warranties, express or implied, including
* warranties of performance, merchantability or fitness for any particular
* purpose.
*
* Please cite the author in any work or product based on this material.
*
* ===========================================================================
*
* File Name: ni_encr.c
*
* Author: Epstein
*
* Version Creation Date: 2/14/94
*
* $Revision: 4.0 $
*
* File Description:
* Supports RSAREF-based encryption for NCBI Network Services client-server
* architecture
*
*
* Modifications:
* --------------------------------------------------------------------------
* Date Name Description of modification
* ------- ---------- -----------------------------------------------------
* 02/22/94 Epstein Fix reading of public keys from config. file, and
* initialization of random data structure for RSA
* encryption.
* 03/04/94 Epstein Reduce memory leakage, avoid ErrPost error if unable
* to open public-key file.
* 03/09/94 Epstein Add length parameter to NI_LoadPrivKey(), add code
* which allows {Transient}SetAppParam() to provide
* some help in providing an unbreakable key. Also
* use high-granularity timing in generating random
* key, where available.
* 07/14/94 Epstein Pad buffer more efficiently in DoDesWrite().
*
*
* RCS Modification History:
* $Log: ni_encr.c,v $
* Revision 4.0 1995/07/26 13:56:32 ostell
* force revision to 4.0
*
* Revision 1.8 1995/05/17 17:52:00 epstein
* add RCS log revision history
*
*/
#include <ncbi.h>
#include <ni_types.h>
#include <global.h>
#include <des.h>
#include <rsaref.h>
#ifdef OS_UNIX
#include <sys/time.h>
#endif /* OS_UNIX */
#define ENCR_DES_TYPE 1
#define ENCR_DES_STATE_IDLE 0
#define ENCR_DES_STATE_GOT1LENBYTE 1
#define ENCR_DES_STATE_INSTREAM 2
/*
* Purpose: Encrypts a buffer using DES
*
* Parameters:
* encr Encryption data structure, includes Cypher-block-chaining info
* buf Input buffer
* len Length of buf
* tmpbuf Output buffer
*
* Returns:
* The length of the resulting encrypted data
*
* Description:
* Encodes the specified input buffer using two bytes which contain
* the length of the _plaintext_ data which follows, followed by
* the encrypted text. Thus, for example, an input buffer of
* length 9 will result in 0x0, 0x9, followed by 16 bytes of
* encrypted data.
*
* Note:
* For safety, the output buffer must be large enough to accomodate
* the two-byte header, plus the length of the input buffer, plus
* an additional seven bytes.
*
* DES cipher-block chaining (CBC) is used, and the CBC information
* is encoded in the desWriteContext data structure.
*/
static Int4
DoDesWrite(NI_EncrDataPtr encr, CharPtr buf, int len, CharPtr tmpbuf)
{
int encrLen;
UcharPtr encrBuf;
UcharPtr outbuf = (UcharPtr) tmpbuf;
outbuf[0] = len / 256; /* high order byte */
outbuf[1] = len % 256; /* low order byte */
encrLen = ((len + 7) / 8) * 8;
encrBuf = (UcharPtr) MemNew(encrLen);
/* pad with zeros */
MemSet ((CharPtr) &encrBuf[len], '\0', encrLen - len);
MemCpy ((CharPtr) encrBuf, buf, len);
DES_CBCUpdate ((DES_CBC_CTX PNTR) encr->desWriteContext, &outbuf[2],
encrBuf, encrLen);
MemFree (encrBuf);
return (encrLen + 2);
}
/*
* Purpose: Encryption write-filter for DES
*
* Parameters:
* mhvoid Pointer to message handle data structure
* buf Input buffer
* len Length of buf
* tmpbuf Output buffer
*
* Returns:
* The length of the resulting encrypted data
*
* Description:
* Validates the input and then processes the data using
* DoDesWrite().
*/
static Int4
DesWriteFilt(VoidPtr mhvoid, CharPtr buf, int len, CharPtr tmpbuf)
{
NI_HandPtr mh = (NI_HandPtr) mhvoid;
if (len <= 0 || tmpbuf == NULL || buf == NULL || mh == NULL ||
mh->encryption == NULL)
return 0;
return DoDesWrite(mh->encryption, buf, len, tmpbuf);
}
/*
* Purpose: Decrypts a buffer using DES
*
* Parameters:
* encr Encryption data structure, includes Cypher-block-chaining info
* buf Input buffer containing encrypted data, and output plaintext
* bytesRead Length of input data in buf
* len Max # of bytes which will fit in buf (requested read length)
*
* Returns:
* The length of the resulting plaintext which has been processed
*
* Description:
* Decodes the specified input buffer, using a protocol which
* consists of two bytes of length information (realDataLeft)
* followed by bytesToRead bytes of encrypted data, where bytesToRead
* is realDataLeft padded out to a multiple of eight bytes.
*
* The algorithm uses a state machine to process as much of the input
* buffer as possible, and to store the remainder of the unprocessed
* input data in encr->deferredData.
*
*
* Note:
*
* DES cipher-block chaining (CBC) is used, and the CBC information
* is encoded in the desReadContext data structure. Also note that
* the history of the CBC consists of the entire communications
* session between client and server up to this point in time.
*/
static Int4
DoDesRead(NI_EncrDataPtr encr, CharPtr buf, int bytesRead, int len)
{
UcharPtr scratchInbuf;
UcharPtr ip; /* ptr to next byte in scratchInbuf */
Int4 retval;
Int2 roomInBuffer;
Int2 avail;
Int2 bytesToDecrypt;
Int2 bytesToCopy;
UcharPtr scratchOutbuf;
Boolean done;
if (bytesRead <= 0 || buf == NULL || encr == NULL)
return 0;
if (encr->state == ENCR_DES_STATE_IDLE)
{
encr->numDeferredBytes = 0;
encr->realDataLeft = 0;
encr->bytesToRead = 0;
}
if ((scratchInbuf = (UcharPtr) MemNew(bytesRead + encr->numDeferredBytes)) ==
NULL)
return 0;
ip = scratchInbuf;
MemCpy ((CharPtr) scratchInbuf, (CharPtr) encr->deferredData,
encr->numDeferredBytes);
MemCpy ((CharPtr) &scratchInbuf[encr->numDeferredBytes], buf, bytesRead);
bytesRead += encr->numDeferredBytes;
encr->numDeferredBytes = 0;
retval = 0;
done = FALSE;
while (bytesRead > 0 && ! done)
{
switch (encr->state) {
case ENCR_DES_STATE_IDLE:
if (bytesRead == 1)
{
encr->realDataLeft = *ip++;
encr->state = ENCR_DES_STATE_GOT1LENBYTE;
done = TRUE;
bytesRead--;
} else {
encr->realDataLeft = ip[0] * 256 + ip[1];
encr->bytesToRead = ((encr->realDataLeft + 7) / 8) * 8;
encr->numDeferredBytes = 0;
ip += 2;
bytesRead -= 2;
encr->state = ENCR_DES_STATE_INSTREAM;
}
break;
case ENCR_DES_STATE_GOT1LENBYTE:
encr->realDataLeft = encr->realDataLeft * 256 + *ip++;
encr->bytesToRead = ((encr->realDataLeft + 7) / 8) * 8;
encr->numDeferredBytes = 0;
bytesRead--;
encr->state = ENCR_DES_STATE_INSTREAM;
break;
case ENCR_DES_STATE_INSTREAM:
avail = MIN(encr->bytesToRead, bytesRead);
roomInBuffer = len - retval;
bytesToDecrypt = (MIN(roomInBuffer, avail) / 8) * 8;
if (bytesToDecrypt <= 0)
{
if (roomInBuffer >= MAX(encr->realDataLeft, 0))
{ /* we can squeeze this in */
bytesToDecrypt = 8;
} else {
done = TRUE;
break;
}
}
scratchOutbuf = (UcharPtr) MemNew(bytesToDecrypt);
DES_CBCUpdate ((DES_CBC_CTX PNTR) encr->desReadContext,
scratchOutbuf, ip, bytesToDecrypt);
bytesToCopy = MIN(encr->realDataLeft, bytesToDecrypt);
MemCpy (buf, (CharPtr) scratchOutbuf, bytesToCopy);
MemFree (scratchOutbuf);
buf += bytesToCopy;
retval += bytesToCopy;
ip += bytesToDecrypt;
bytesRead -= bytesToDecrypt;
encr->bytesToRead -= bytesToDecrypt;
encr->realDataLeft -= bytesToDecrypt;
if (encr->bytesToRead <= 0)
{
encr->state = ENCR_DES_STATE_IDLE;
encr->numDeferredBytes = 0;
encr->realDataLeft = 0;
encr->bytesToRead = 0;
}
break;
}
}
if (bytesRead > 0)
{
encr->numDeferredBytes = bytesRead;
if (bytesRead > sizeof(encr->deferredData))
{
ErrPostEx(SEV_ERROR, 0, 0, "Too much deferred decryption data %d bytes", bytesRead);
} else {
MemCpy ((CharPtr) encr->deferredData, (CharPtr) ip, bytesRead);
}
}
MemFree (scratchInbuf);
return retval;
}
/*
* Purpose: DES read filter
*
* Parameters:
* mhvoid Pointer to message handle data structure
* buf Input buffer containing encrypted data, and output plaintext
* bytesRead Length of input data in buf
* len Max # of bytes which will fit in buf (requested read length)
* extra_buf unused, but required for NI_ReadFilt declaration
* extra_buf_len unused, but required for NI_ReadFilt declaration
*
* Returns:
* The length of the resulting plaintext which has been processed
*
* Description:
* Uses DoDesRead() to process input data, and returns to caller
*/
static Int4
DesReadFilt(VoidPtr mhvoid, CharPtr buf, int bytesRead, int len, CharPtr PNTR extra_buf, Int4Ptr extra_buf_len)
{
NI_HandPtr mh = (NI_HandPtr) mhvoid;
if (bytesRead <= 0 || buf == NULL || mh == NULL ||
mh->encryption == NULL)
return 0;
return DoDesRead(mh->encryption, buf, bytesRead, len);
}
/*
* Purpose: Setup DES encryption for this message handle
*
* Parameters:
* mh Pointer to message handle data structure
* desKey DES key to be used for the life of this session
*
* Returns:
* TRUE if setup was successful, FALSE otherwise
*
* Description:
* Allocates an encryption data structure to attach to the message
* handle, as well as the RSAREF data structures for both reading
* and writing data. Note that the read and write data structures
* are each handling an independent half-duplex channel, i.e,
* either client->server or server->client data.
*
* Note:
* A caller which uses this function must also call
* NI_DestroyEncrStruct() when it is time to destroy the message
* handle.
*/
Boolean LIBCALL
NI_SetupDESEncryption(NI_HandPtr mh, UcharPtr desKey)
{
Uchar iv[8];
NI_EncrDataPtr encr;
if (mh->encryption != NULL)
return FALSE;
if ((encr = MemNew(sizeof(*encr))) == NULL)
return FALSE;
mh->encryption = encr;
encr->encrType = ENCR_DES_TYPE; /* the only possibility, for now */
encr->state = ENCR_DES_STATE_IDLE;
encr->write_filter = DesWriteFilt;
encr->read_filter = DesReadFilt;
encr->desWriteContext = (DES_CBC_CTX PNTR) MemNew(sizeof(DES_CBC_CTX));
MemSet((CharPtr) iv, '\0', sizeof(iv));
DES_CBCInit((DES_CBC_CTX PNTR) encr->desWriteContext, desKey, iv, TRUE);
encr->desReadContext = (DES_CBC_CTX PNTR) MemNew(sizeof(DES_CBC_CTX));
MemSet((CharPtr) iv, '\0', sizeof(iv));
DES_CBCInit((DES_CBC_CTX PNTR) encr->desReadContext, desKey, iv, FALSE);
return TRUE;
}
/*
* Purpose: Seed the random number generator if necessary
*
* Description:
* If this function has not previously been called, it seeds the NCBI
* random number generator with the best pseudo-random data available
* on all systems, namely the current time in seconds, and a notion
* of the application's process ID. A high-granularity time is
* also included when available.
*
* Note:
* It would be helpful to have another NCBI function which returns
* the highest-granularity time available, e.g., many systems have
* microsecond and/or ticks available. Any other creative data
* available on this system (e.g., for UNIX systems, how many inodes
* are in use in the root filesystem of this computer) would also be
* helpful to help defeat malicious attempts to crack the security
* of this encryption subsystem.
*/
static void
SetRandomSeed(void)
{
static Boolean inited = FALSE;
Int4 highGranularity = 0;
#ifdef OS_UNIX
struct timeval tv;
gettimeofday(&tv, NULL);
highGranularity = tv.tv_usec;
#endif
#ifdef OS_MAC
highGranularity = clock();
#endif
#ifdef WIN_MSWIN
highGranularity = (Int4) GetCurrentTime();
#endif
if (! inited)
{
RandomSeed ((long) (GetSecs() | Nlm_GetAppProcessID() | highGranularity));
inited = TRUE;
}
}
/*
* Purpose: Initialize an RSAREF random data structure used for RSA encryption
*
* Parameters:
* randomStruct The data structure to be populated
*
* Description:
* Seed the random number generator if necessary, create a random
* R_RANDOM_STRUCT data structure, and populate it with
* pseudo-random data. When available, data from the NCBI config.
* file is exclusive-ORed into each pseudo-random number, so
* that an RSA key cannot subsequently be broken by trying all
* 2^^32 possible values of the random number generator.
*/
static void InitRandomStruct (randomStruct)
R_RANDOM_STRUCT *randomStruct;
{
unsigned int bytesNeeded;
long ran;
Int4 seednum = 0;
Char buf[22];
Char moredata[10];
SetRandomSeed();
R_RandomInit (randomStruct);
while (1) {
R_GetRandomBytesNeeded (&bytesNeeded, randomStruct);
if (bytesNeeded == 0)
break;
ran = RandomNum();
sprintf (buf, "CONFOUND_%d", seednum);
GetAppParam("NCBI", "NET_SERV", buf, "0", moredata, sizeof moredata);
ran ^= atoi(moredata);
seednum++;
R_RandomUpdate (randomStruct, (UcharPtr) &ran, MIN(bytesNeeded, sizeof ran));
}
}
/*
* Purpose: Convert pub encryption key from RSAREF format to internal NCBI fmt
*
* Parameters:
* publicKey Key in RSAREF format
*
* Returns:
* Key in NCBI format, or NULL if an error occurred
*
* Description:
* Convert RSAREF public key data structure into a form which is
* suitable for being stored and transmitted in ASN.1
*/
static NI_PubKeyPtr
PubKeyToInternalFormat(R_RSA_PUBLIC_KEY PNTR publicKey)
{
NI_PubKeyPtr retval = (NI_PubKeyPtr) MemNew(sizeof(*retval));
if (retval == NULL || publicKey == NULL)
return NULL;
retval->bits = publicKey->bits;
retval->modulus = BSNew(sizeof(publicKey->modulus));
BSWrite(retval->modulus, (VoidPtr) publicKey->modulus, sizeof(publicKey->modulus));
retval->exponent = BSNew(sizeof(publicKey->exponent));
BSWrite(retval->exponent, (VoidPtr) publicKey->exponent, sizeof(publicKey->exponent));
return retval;
}
/*
* Purpose: Convert pub encryption key from internal NCBI format to RSAREF fmt
*
* Parameters:
* internal Key in NCBI format
*
* Returns:
* Key in RSAREF format, or NULL if an error occurred
*
* Description:
* Produce RSAREF public key data structure from a form which is
* suitable for being stored and transmitted in ASN.1
*/
static R_RSA_PUBLIC_KEY PNTR
InternalToPubKeyFormat(NI_PubKeyPtr internal)
{
R_RSA_PUBLIC_KEY PNTR retval;
if (internal == NULL || internal->modulus == NULL ||
internal->exponent == NULL)
return NULL;
retval = (R_RSA_PUBLIC_KEY PNTR) MemNew(sizeof(*retval));
retval->bits = internal->bits;
BSSeek (internal->modulus, 0, SEEK_SET);
BSSeek (internal->exponent, 0, SEEK_SET);
BSRead(internal->modulus, retval->modulus, sizeof(retval->modulus));
BSRead(internal->exponent, retval->exponent, sizeof(retval->exponent));
return retval;
}
/*
* Purpose: Compare two public encryption keys for equality
*
* Parameters:
* x Public key #1
* y Public key #2
*
* Returns:
* TRUE if keys match, FALSE otherwise
*
* Description:
* Converts keys into RSAREF format, because these are flat data
* structures and hence easy to compare.
*/
Boolean LIBCALL
NI_PubKeysEqual(NI_PubKeyPtr x, NI_PubKeyPtr y)
{
R_RSA_PUBLIC_KEY PNTR xRsa = InternalToPubKeyFormat(x);
R_RSA_PUBLIC_KEY PNTR yRsa = InternalToPubKeyFormat(y);
Boolean retval;
if (xRsa == NULL && yRsa== NULL)
return TRUE;
if (xRsa == NULL || yRsa== NULL)
{
retval = FALSE;
} else {
retval = MemCmp((CharPtr) xRsa, (CharPtr) yRsa, sizeof (*xRsa)) == 0;
}
MemFree (xRsa);
MemFree (yRsa);
return retval;
}
/*
* Purpose: Pseudo-randomly generate an 8-byte DES key
*
* Parameters:
* desKey Resulting DES key
*
* Description:
* Generates 8-byte DES key, grabbing 2 bytes from each of 4 pseudo-
* randomly generated long integers.
*
* Note:
* Only 2 bytes are used from the long integer, because it's
* conceivable that a machine exists without 4-byte long integers.
* In hindsight, sizeof(long) could be used to determine how much to
* use, but this is a reasonable implementation.
*/
void
NI_GenerateDESKey(UcharPtr desKey)
{
Int2 i;
long ran;
SetRandomSeed();
for (i = 0; i < 8;)
{
ran = RandomNum();
desKey[i++] = ran & 255;
desKey[i++] = (ran >> 8) & 255;
}
}
/*
* Purpose: Generate pub encryption public + private keys, and write to files
*
* Parameters:
* bits Length of key modulus in bits, within a restricted range
* pubAip AsnIoPtr to where public-key should be stored
* privFp File pointer to where private key should be stored
*
* Returns:
* TRUE if operations were successful, FALSE otherwise
*
* Description:
* Generates public and private keys using RSAREF function, and then
* output to AsnIoPtr and file pointer.
*
* Note:
* An AsnIoPtr is used for the public key, because the public key
* must be transmittable in a canonical format. Since private keys
* are never transmitted, a single block of memory is used for
* private keys, and private keys are stored in a single chunk on
* disk. This reduces the number of special data structures and
* ASN.1 object loaders which needed to be constructed to add
* encryption to NCBI Network Services.
*/
Boolean LIBCALL
NI_GenAndWritePEMKeys(Int2 bits, AsnIoPtr pubAip, FILE *privFp)
{
R_RSA_PUBLIC_KEY publicKey;
R_RSA_PRIVATE_KEY privateKey;
R_RSA_PROTO_KEY protoKey;
R_RANDOM_STRUCT randomStruct;
int retval;
AsnModulePtr amp;
AsnTypePtr pubAtp;
NI_PubKeyPtr internalPub;
NI_HandPtr dummyHand;
if (bits < MIN_RSA_MODULUS_BITS || bits > MAX_RSA_MODULUS_BITS)
return FALSE;
if (pubAip == NULL || privFp == NULL)
return FALSE;
/* create a dummy message handle to ensure that ASN.1 is loaded */
dummyHand = (NI_HandPtr) MsgMakeHandle(FALSE);
MsgDestroyHandle(dummyHand);
if ((amp = AsnAllModPtr()) == NULL)
return FALSE;
if ((pubAtp = AsnTypeFind(amp, "RSA-Pubkey")) == NULL)
return FALSE;
InitRandomStruct (&randomStruct);
protoKey.bits = bits;
protoKey.useFermat4 = 1;
retval = R_GeneratePEMKeys(&publicKey, &privateKey, &protoKey, &randomStruct);
if (retval != 0)
{
ErrPostEx(SEV_ERROR, 0, 0, "Error when generating PEM keys %d", retval);
}
internalPub = PubKeyToInternalFormat(&publicKey);
NI_WritePubKey(pubAip, pubAtp, internalPub);
FileWrite(&privateKey, sizeof(privateKey), 1, privFp);
return TRUE;
}
/*
* Purpose: Write a public key to a standard location on client machines
*
* Parameters:
*
* pub The public-key to be written to standard file
*
* Returns:
* TRUE if operations were successful, FALSE otherwise
*
* Description:
* Writes public-key to a file in the DATA directory.
* Alternatively, the public-key could be stored anywhere ...
* originally it was stored in the NCBI configuration file.
*/
Boolean LIBCALL
NI_WritePubKeyToConfig (NI_PubKeyPtr pub)
{
Char fname[PATH_MAX];
AsnIoPtr aip;
AsnModulePtr amp;
AsnTypePtr pubAtp;
Boolean retval;
NI_HandPtr dummyHand;
if (pub == NULL)
{
return FALSE;
}
/* create a dummy message handle to ensure that ASN.1 is loaded */
dummyHand = (NI_HandPtr) MsgMakeHandle(FALSE);
MsgDestroyHandle(dummyHand);
if ((amp = AsnAllModPtr()) == NULL)
return FALSE;
if ((pubAtp = AsnTypeFind(amp, "RSA-Pubkey")) == NULL)
return FALSE;
if (! FindPath("ncbi", "ncbi", "data", fname, sizeof (fname)))
{
ErrPost(CTX_NCBIOBJ, 1, "FindPath failed");
return FALSE;
}
StringCat(fname, "pubkey.enc");
if ((aip = AsnIoOpen(fname, "w")) == NULL)
{
return FALSE;
}
NI_WritePubKey(aip, pubAtp, pub);
AsnIoClose(aip);
return TRUE;
}
/*
* Purpose: Read a public key from a standard configuration location
*
* Returns:
* A pointer to the allocated public-key, or NULL if failed
*
* Description:
* Reads public-key from a file in the DATA directory.
* Alternatively, the public-key could be stored anywhere ...
* originally it was stored in the NCBI configuration file.
*/
NI_PubKeyPtr LIBCALL
NI_ReadPubKeyFromConfig (void)
{
Char fname[PATH_MAX];
AsnIoPtr aip;
NI_PubKeyPtr pub;
FILE *fp;
if (! FindPath("ncbi", "ncbi", "data", fname, sizeof (fname)))
{
ErrPost(CTX_NCBIOBJ, 1, "FindPath failed");
return NULL;
}
StringCat(fname, "pubkey.enc");
/* try opening the file first, to suppress AsnIoOpen messages */
if ((fp = FileOpen(fname, "r")) == NULL)
{
return NULL;
} else {
FileClose(fp);
}
if ((aip = AsnIoOpen(fname, "r")) == NULL)
{
FileRemove(fname);
return NULL;
}
pub = (NI_PubKeyPtr) NI_MakePubKey();
if (NI_ReadPubKey(aip, NULL, pub) < 0)
{
NI_DestroyPubKey(pub);
pub = NULL;
}
AsnIoClose(aip);
return pub;
}
/*
* Purpose: Make a copy of a public key
*
* Parameters:
* orig The key to be copied
*
* Returns:
* A pointer to the copy of the public-key, or NULL if failed
*
* Description:
* Makes a copy of a public key
*/
NI_PubKeyPtr LIBCALL
NI_PubKeyDup (NI_PubKeyPtr orig)
{
NI_PubKeyPtr dup;
if (orig == NULL)
return NULL;
dup = MemNew(sizeof(*dup));
dup->bits = orig->bits;
dup->modulus = BSDup(orig->modulus);
dup->exponent = BSDup(orig->exponent);
return dup;
}
/*
* Purpose: Load a private-key from the specified file pointer
*
* Parameters:
* fp File pointer from which to read private key
* privKeyLenPtr Pointer to where the length of private key may be stored
*
* Returns:
* A pointer to the resulting data structure, or NULL if unsuccessful
*
* Description:
* Reads private key from data file.
*/
VoidPtr LIBCALL
NI_LoadPrivKey(FILE *fp, Int2Ptr privKeyLenPtr)
{
R_RSA_PRIVATE_KEY PNTR privKey;
privKey = (R_RSA_PRIVATE_KEY PNTR) MemNew(sizeof(*privKey));
FileRead(privKey, sizeof(*privKey), 1, fp);
if (privKeyLenPtr != NULL)
{
*privKeyLenPtr = sizeof(*privKey);
}
return privKey;
}
/*
* Purpose: Perform public-key decryption
*
* Parameters:
* pKey Private key
* plainText Pointer to resulting plaintext
* cipherText Ciphertext to be decrypted
* cipherTextLen Length of cipherText
*
* Returns:
* The length of resulting plaintext, or a negative error code
*
* Description:
* Decrypts the specified ciphertext using the specified private
* key. Subsequently resizes the resulting plaintext to be only
* as large as is needed.
*
* Note:
* The caller must free the pointer to the resulting plaintext.
*/
Int2 LIBCALL
NI_PubKeyDecrypt(VoidPtr pKey, UcharPtr PNTR plainText, UcharPtr cipherText, Int2 cipherTextLen)
{
R_RSA_PRIVATE_KEY PNTR privKey = (R_RSA_PRIVATE_KEY PNTR) pKey;
int plainTextLen;
UcharPtr pText1, pText2;
if (pKey == NULL || plainText == NULL || cipherText == NULL)
return -1;
*plainText = NULL;
/* plain text is certainly shorter than ciphertext */
pText1 = (UcharPtr) MemNew(cipherTextLen);
if (RSAPrivateDecrypt(pText1, &plainTextLen, cipherText, cipherTextLen, privKey) != 0)
{
MemFree (pText1);
return -2;
}
pText2 = (UcharPtr) MemDup(pText1, plainTextLen);
MemFree (pText1);
*plainText = pText2;
return ((Int2) plainTextLen);
}
/*
* Purpose: Perform public-key encryption
*
* Parameters:
* pub Public key
* plainText Plaintext to be encrypted
* plainTextLen Length of plainText
* cipherText Pointer to resulting ciphertext
*
* Returns:
* The length of resulting ciphertext, or a negative error code
*
* Description:
* Encrypts the specified plaintext using the specified public
* key. Subsequently resizes the resulting ciphertext to be only
* as large as is needed.
*
* Note:
* The caller must free the pointer to the resulting ciphertext.
*/
Int2 LIBCALL
NI_PubKeyEncrypt(NI_PubKeyPtr pub, UcharPtr plainText, Int2 plainTextLen, UcharPtr PNTR cipherText)
{
R_RSA_PUBLIC_KEY PNTR pubKeyPtr;
R_RANDOM_STRUCT randomStruct;
UcharPtr cipher, cipher2;
int cipherTextLen = 0;
if (pub == NULL || plainText == NULL || cipherText == NULL)
{
return -1;
}
*cipherText = NULL;
if ((pubKeyPtr = InternalToPubKeyFormat(pub)) == NULL)
{
return -2;
}
cipher = (UcharPtr) MemNew(plainTextLen * 2 + 64);
InitRandomStruct (&randomStruct);
if (RSAPublicEncrypt(cipher, &cipherTextLen, plainText, plainTextLen, pubKeyPtr, &randomStruct) != 0)
{
MemFree (cipher);
MemFree (pubKeyPtr);
return -3;
}
MemFree (pubKeyPtr);
/* reduce to the proper length */
cipher2 = (UcharPtr) MemDup(cipher, cipherTextLen);
MemFree (cipher);
*cipherText = cipher2;
return ((Int2) cipherTextLen);
}
/*
* Purpose: Free an encryption data structure, and erase secret data
*
* Parameters:
* encr Encryption data structure to be destroyed
*
*
* Description:
* Frees an encryption data structure, and erases secret data
* which could be used by a hostile party to break the encryption.
* The caller must free the pointer to the resulting ciphertext.
*/
void
NI_DestroyEncrStruct (NI_EncrDataPtr encr)
{
if (encr == NULL)
return;
if (encr->desReadContext != NULL)
{
/* clear this memory for security reasons */
MemSet(encr->desReadContext, '\0', sizeof(DES_CBC_CTX));
MemFree(encr->desReadContext);
}
if (encr->desWriteContext != NULL)
{
/* clear this memory for security reasons */
MemSet(encr->desWriteContext, '\0', sizeof(DES_CBC_CTX));
MemFree(encr->desWriteContext);
}
MemFree(encr);
}
/*
* Purpose: Indicates whether encryption is available
*
* Returns: Always TRUE for this file, always FALSE for stub file
*
*
* Description:
* Indicates to the caller whether encryption is available, and
* whether or not it is safe to call the other encryption
* functions.
*/
Boolean LIBCALL
NI_EncrAvailable(void)
{
return TRUE;
}